import java.io.*;
import java.util.*;

class DataParser{
  String FILENAME = "history3Months.txt";

  HashMap sitesByTimeMap;  //Hashmap of SitesByTime objects, key is time
  HashMap siteInfoMap;  //Hashmap of WebSiteInfo objects, key is website name
  ArrayList allWebSites;  //Arraylist of all sites in string

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  DataParser(){
    sitesByTimeMap = new HashMap();
    siteInfoMap = new HashMap();
    allWebSites = new ArrayList();

    parseFile();  //read each line from history file and build the data structure
     
    getAllSites();  //get all sites from WebSiteInfo hashmap and fill allSites arraylist and print them in a file named allWebSites.txt
    
    //printInfo();
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  void parseFile(){
    BufferedReader reader;
    reader = createReader(dataPath("")+FILENAME);
    boolean EOF = false;
    String lines;

    while(!EOF){  
      try{
        lines = reader.readLine();
      }
      catch(IOException e){     
        e.printStackTrace();
        lines = null;
      }

      if(lines ==null){
        EOF = true;
      }
      else{   
        /*-------------------------------------------------------------
         Fill up the siteInfoMap      
         ---------------------------------------------------------------*/
        //println(lines); 
        String pieces[] = split(lines, TAB);
        //println(pieces);
        
        String domain = "";

        String matchPattern = "(.*)//(.*?/)";  //pattern for extracting domain name
        Pattern p = Pattern.compile(matchPattern);
        Matcher m = p.matcher(pieces[0]);

        String referrer = "";
        if( !pieces[4].equals("") ){
          Matcher mr = p.matcher(pieces[4]);  
          if(mr.find()){
            referrer = mr.group(2).substring(0, mr.group(2).length()-1);
          }
        }

        if(m.find()){
          domain = m.group(2).substring(0, m.group(2).length()-1);  //Domain name extracted using reg exp contains / at end, get rid of it
          //println(domain);

          //domain is the key
          if( siteInfoMap.containsKey(domain) ){  //This site already added, so update attributes
            WebSiteInfo webInfo = (WebSiteInfo)siteInfoMap.get(domain);  
            webInfo.visitCount++;  //increment visit count
            webInfo.timeStampList.add( pieces[1] );  //add tiemstamp 

            if( !pieces[3].equals("") ){
              if( !webInfo.visitTypeList.contains(pieces[3]) ){
                webInfo.visitTypeList.add(pieces[3]);  //add visit types
              }
            }

            if( !referrer.equals("") ){
              if( !webInfo.referrerList.contains(referrer) ){
                webInfo.referrerList.add(referrer);  //add referrers
              }                 
            }
          }
          else{  //This is a new site
            WebSiteInfo webInfo = new WebSiteInfo();
            webInfo.siteName = domain;  //name of the site
            webInfo.visitCount = 1;  //This is first visit
            webInfo.timeStampList.add( pieces[1] );  //add tiemstamp 
            if( !pieces[3].equals("") ){
              webInfo.visitTypeList.add(pieces[3]);  //add visit types
            }
            if( !referrer.equals("") ){
              webInfo.referrerList.add(referrer);  //add referrers
            }
            siteInfoMap.put(domain, webInfo );  //add it to hashmap
          }
        }

        /*-------------------------------------------------------------
         Fill up the sitesByTimeMap      
         ---------------------------------------------------------------*/
        //println(pieces[1]);
        String date_time[] = split(pieces[1], ' ');
        //println(date_time);
        String mon_day_year[] = split(date_time[0], '/');
        //println(mon_day_year);
        String hour_min_sec[] = split(date_time[1], ':');
        //println(hour_min_sec);
        //convert 12-hour system to 24-hour system
        int hourVal = 0;
        if( date_time[2].equals("PM") ){
          int tempHourVal = parseInt( hour_min_sec[0] );
          if(tempHourVal >= 1 && tempHourVal <= 11)
            hourVal = tempHourVal+12;  
        }
        else{
          hourVal = parseInt( hour_min_sec[0] ); 
        } 

        String mon_day_year_hour_Key = mon_day_year[0] + "-" + mon_day_year[1] + "-" + mon_day_year[2] + "-" + hourVal;
        //println(mon_day_year_hour_Key);

        if( sitesByTimeMap.containsKey(mon_day_year_hour_Key) ){  //This timestamp already added, so update attributes
          SitesByTime sitesTimeInfo = (SitesByTime)sitesByTimeMap.get(mon_day_year_hour_Key);  
          sitesTimeInfo.totalCountThisHour++;
          ////sitesTimeInfo.sitesList.add( domain );  
          if( sitesTimeInfo.sitesMapByHours.containsKey(domain) ){  //This site is added earlier, so increment the count only
            SiteCountHourly sch = (SiteCountHourly)sitesTimeInfo.sitesMapByHours.get(domain);   
            sch.countHourly++;   
          }
          else{  //this is a new site visited this hour
            SiteCountHourly sch = new SiteCountHourly();
            sch.site = domain;
            sch.countHourly = 1;
            sitesTimeInfo.sitesMapByHours.put(domain, sch);
          }
        }
        else{  //This is a new timestamp
          SitesByTime sitesTimeInfo = new SitesByTime();
          String date[] = split(mon_day_year_hour_Key,'-');
          sitesTimeInfo.date = new Date(Integer.parseInt(date[2])-1900, Integer.parseInt(date[0])-1, Integer.parseInt(date[1])-2, Integer.parseInt(date[3]), 00);  
          sitesTimeInfo.totalCountThisHour = 1;
          ////sitesTimeInfo.sitesList.add( domain );  
          SiteCountHourly sch = new SiteCountHourly();
          sch.site = domain;
          sch.countHourly = 1;
          sitesTimeInfo.sitesMapByHours.put(domain, sch); 
           
          sitesByTimeMap.put(mon_day_year_hour_Key, sitesTimeInfo );  //add it to hashmap
        }
                
      }
    }    
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  void getAllSites(){
    ArrayList allSitesTemp = new ArrayList(siteInfoMap.values());  
    for(int i = 0; i<allSitesTemp.size(); i++){
      WebSiteInfo webInfo = (WebSiteInfo)allSitesTemp.get(i);
      allWebSites.add(webInfo.siteName); 
    }    
    
    //println(allWebSites);
    PrintWriter output = createWriter("allWebSites.txt");
    for(int i = 0; i<allWebSites.size(); i++){
      output.println(allWebSites.get(i));
    }
    
    output.flush();
    output.close();
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  void getAllSitesByDate(Date date){
//    //ArrayList sitesByTime = new ArrayList(sitesByTimeMap.values());  
//    //Collections.sort(sitesByTime); 
//    println(date);   
//
//      
//  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////  
  void printInfo(){
    println("Printing individual sites info............");
    ArrayList allSites = new ArrayList(siteInfoMap.values());  
    for(int i = 0; i<allSites.size(); i++){
      WebSiteInfo webInfo = (WebSiteInfo)allSites.get(i);
      println(webInfo.siteName+" "+webInfo.visitCount+" "+webInfo.timeStampList+" "+webInfo.visitTypeList+" "+webInfo.referrerList);  
    }
    
    println("\nPrinting all sites for a timeslot............");
    ArrayList sitesByTime = new ArrayList(sitesByTimeMap.values());  
    Collections.sort(sitesByTime);
    for(int i = 0; i<sitesByTime.size(); i++){
      SitesByTime sitesTimeInfo = (SitesByTime)sitesByTime.get(i);
      ArrayList sitesThisHour = sitesTimeInfo.getSitesByHour();
      Collections.sort(sitesThisHour);
      println(sitesTimeInfo.date);
      println(sitesTimeInfo.totalCountThisHour);
      for(int j = 0; j<sitesThisHour.size(); j++)
      {
        SiteCountHourly sch = (SiteCountHourly)sitesThisHour.get(j);
        println(sch.site+" "+sch.countHourly);  
      }
    }
  }
}


